import { EventDispatcher } from "../../app_base/base/event/EventDispatcher";
import { Task } from "../../app_base/module/task/Task";
import { TaskQueue } from "../../app_base/module/task/TaskQueue";
import { app } from "../../base";

/**
* 预加载资源列表
* @example
* //预加载主包内的资源
* "main://path/to/main/assets"
* //预加载动态资源中的资源和文件夹
* "MainRes://path/to/MainRes/assets"
* "MainRes://path/to/MainRes/dir/"
* //预加载其他包中的资源和文件夹
* "bundleName://path/to/other/bundle/assets"
* "bundleName://path/to/other/bundle/dir/"
* //预加载远程服务器上的资源
* "https://image.hnquyou.com/path/to/remote/sound.mp3"
* "https://image.hnquyou.com/path/to/remote/image.png"
*/
const PRE_LOAD_REOURCES: string[] = [
    "MainRes://view/main/",
];

/**
 * 预加载资源
 */
export class TaskLoadRes extends Task {
    private _logLabel: string;
    /**
     * 开始预加载资源
     * @param preLoadList 资源列表
     */
    start(): void {
        this._logLabel = `[预加载-加载资源] ${PRE_LOAD_REOURCES.length}个 ...done`;
        console.time(this._logLabel);
        if (!PRE_LOAD_REOURCES.length) {
            this.onComplete();
            return;
        }
        app.res.preload(PRE_LOAD_REOURCES, this);
    }

    onComplete(): void {
        console.timeEnd(this._logLabel);
        super.onComplete();
    }
}

export class TaskLoadBundle extends EventDispatcher {
    private _task: TaskQueue = new TaskQueue();

    private _resPaths: string[] = [];

    /**
     * 加载资源
     * @param paths - `bundleName://path/to/asset`目标素材的资源地址
     * @param assetType - 可选参数，cocos资源类型（cc.Asset子类），当返回类型不是预期类型时，需要手动指定，如cc.SpriteFrame
     * @returns 全部失败后返回null
     * 
     * @example 
     * //加载主包内的素材
     * load("main://path/to/asset")
     * //加载动态资源中的素材
     * load("resources://path/to/asset")
     * //加载其他包中的资源
     * load("bundleName://path/to/image")
     * //加载远程服务器上的资源
     * load("https://path/to/asset.mp3")
     * load("https://path/to/image.png")
     * //加载文件夹
     * load("bundleName://path/to/dir/")
     */
    public constructor(paths: string[]) {
        super();
        this._resPaths = paths;
    }

    /**
     * 开始加载
     * @param data 
     */
    public load(): void {
        this._task.reset();

        for (let path of this._resPaths) {
            this._task.addTask(new TaskLoadDir(path));
        }

        //并行执行后续任务
        this._task.on(Task.Event.COMPLETE, this, this._onTaskEvent);
        this._task.on(Task.Event.ERROR, this, this._onTaskEvent);
        this._task.on(Task.Event.PROGRESS, this, this._onTaskEvent);
        this._task.start();
    }

    private _onTaskEvent(type: string, task: Task, ...datas: any[]): void {
        this.event(type, [task, ...datas]);
    }

    public destroy(): void {
        this._task && this._task.destroy();
        this._task = null;
    }
}

/**
 * 加载关卡资源文件夹或文件
 */
export class TaskLoadDir extends Task {
    private _logLabel: string;
    private _dirPath: string = '';

    public constructor(dirPath: string) {
        super();
        this._dirPath = dirPath;
    }

    /**
     * 开始预加载资源
     * @param preLoadList 资源列表
     */
    start(): void {
        this._logLabel = `[加载-文件夹] ${this._dirPath} ...done`;
        console.time(this._logLabel);
        if (!this._dirPath) {
            this.onComplete();
            return;
        }
        app.res.load(this._dirPath, cc.Asset, this);
    }

    onComplete(): void {
        console.timeEnd(this._logLabel);
        super.onComplete();
    }
}